package com.googlecode.cswish.oosearch;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import com.googlecode.cswish.struts.spring.GenericService;

/**
 * Wrap a query result using lazy mode
 * 
 * @author Jerry.Feng Date: 2008-9-20
 */
public class QueryList<E> implements List<E>, Serializable {
	private GenericService service;
	
	private String ql;	
	private Object[] parameters;
	
	// result information
	private EntityManager em = null;
	private int fetchSize = 10;		// default value
	private int count = -1;
	private Map<Integer, List<E>> cache = new HashMap<Integer, List<E>>();
	
	// the next list, it's a link structure
	private QueryList<E> next;
	
	public QueryList(Collection<? extends E> c) {
		count = c.size();
		
		fetchSize = count;
		if (c instanceof List) {
			cache.put(new Integer(1), (List<E>) c);
		} else {
			cache.put(new Integer(1), new ArrayList<E>(c));
		}
	}
	
	public QueryList(String ql, Object[] parameters) {
		this.ql = ql;
		this.parameters = parameters;
	}
	
	private EntityManager getEntityManager() {
		// TODO:
		return null;
	}
	
	private List<E> search(int from, int to) {
		Query query = getEntityManager().createQuery(ql);
		if (parameters != null) {
    		for (int i = 0; i < parameters.length; i++) {
				query.setParameter(i + 1, parameters[i]);
			}
    	}
		query.setFirstResult(from);
		query.setMaxResults(to);
		List<E> data = query.getResultList();
		return data;
	}
	
	private int getCount() {
		int index = ql.lastIndexOf(" order by ");
		if (index > 0) {
			ql = ql.substring(0, index);
		}
		
		// get the total count
		String countHql = "select count(a) " + ql;
		Query query = getEntityManager().createQuery(countHql);
		if (parameters != null) {
    		for (int i = 0; i < parameters.length; i++) {
				query.setParameter(i + 1, parameters[i]);
			}
    	}
		
		Object value = query.getSingleResult();
		int count = Integer.parseInt(value.toString());
		return count;
	}

	@Override
	public boolean add(E e) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void add(int index, E element) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean addAll(Collection<? extends E> c) {
		if (c == null || c.size() == 0) {
			return false;
		}
		
		if (next != null) {
			next.addAll(c);
		} else if (c instanceof QueryList){
			next = (QueryList<E>) c;
		} else {
			next = new QueryList<E>(c);
		}		
		return true;
	}

	@Override
	public boolean addAll(int index, Collection<? extends E> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void clear() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean contains(Object o) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public E get(int index) {
		int page = index / fetchSize;
		List<E> data = cache.get(page);
		if (data == null) {
			if (next == null || index < getCount()) {
				int from = page * fetchSize;
				int to = from + fetchSize;
				
				data = search(from, to);
			}
		}
		
		int item = index % fetchSize;
		if (data != null && item < data.size()) {
			// cache current data
			cache.put(page, data);
			
			return data.get(item);
		} else if (next != null) {
			return next.get(index - getCount());
		} else {
			throw new IndexOutOfBoundsException(
					"Index: " + index + ", Size: " + getCount());
		}
	}

	@Override
	public int indexOf(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Iterator<E> iterator() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int lastIndexOf(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public ListIterator<E> listIterator() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ListIterator<E> listIterator(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean remove(Object o) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public E remove(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public E set(int index, E element) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int size() {
		if (count == -1) {
			count = getCount();
		}
		
		return count;
	}

	@Override
	public List<E> subList(int fromIndex, int toIndex) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object[] toArray() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public <T> T[] toArray(T[] a) {
		// TODO Auto-generated method stub
		return null;
	}
}
